import Token
import string
import regex
from ET import GetPreference

def SetEditor(editor):
	global _editor
	_editor=editor

#
# As if the (keycode,flags) would have been typed derictely
#
def DoKeyCode(key,code):
	_editor.DoKey(key,code)

def DoKey(keycode):
	_editor.DoKey(keycode[0],keycode[1])

def DoNamedKey(name):
	"""Like DoKey, but takes a string as argument"""
	DoKey(Token.KeyName2CodeFlags(name))
 
def DoMenuCommand(cmdno):
	try:
		_editor.DoMenuCommand(cmdno)
	except:
#		print "OOPS"
		Bell()
def ForceMenuCommand(cmdno):
	try:
		_editor.ForceMenuCommand(cmdno)
	except:
		Bell()

def GetMenuShortcut(cmdno):
	return _editor.GetMenuShortcut(cmdno)
def SetMenuShortcut(cmdno,shortcut):
	_editor.SetMenuShortcut(cmdno,shortcut)

def DoToken(token):
	_editor.DoKey(token.GetCode(),token.GetFlags())

def DoKeyName(keyname):
	code,flags=KeyName2CodeFlags(keyname)
	_editor.DoKey(code,flags)
def Cut():
	"""Cuts the current selection and puts it on the clipboard."""
	_editor.Cut()

def Copy():
	"""Copies the current selection and puts it on the clipboard. 
	It will not change# the current buffer."""
	_editor.Copy()

#
# 
#
def Paste():
	"""Pastes the clipboard at the current point."""
	_editor.Paste()

########################################################
def GetSelection():
	"""returns a touple: (start,end)"""
	return _editor.GetSelection()

def GetSelectionText():
	"""eturns a string"""
	return _editor.GetSelectionText()

#
# returns a string
# GetText(begin,end) or GetText((begin,end))
#
def GetText(*args):
	return _editor.GetText(args)

def InsertText(string):
	"""Insert text replacing the current selection."""
	return _editor.InsertText(string)

def InsertTextAndSelect(string,rel_pos,len=0):
	"""Insert 'string' and select 'rel_pos' 'len' characters"""
	s,e=GetSelection()
	_editor.InsertText(string)
	SetSelection(s+rel_pos,s+rel_pos+len)

def HasSelection():
	return _editor.HasSelection()
def GetFileName():
	return _editor.GetFileName()
def GetFileType():
	return _editor.GetFileType()
 
def Goto(pos):
	"""Puts the cursor to pos"""
	_editor.Goto(pos)

def RevealLine(line):
	_editor.RevealLine(line)
 
def Up():
	"""Moves the cursor une line up"""
	_editor.Up()
 
def Down():
	"""Moves the cursor one line down."""
	_editor.Down()

def Left():
	"""Moves the cursor one character to the left.
	It will go to the previous line if it is at the end of the line..."""
	_editor.Left()

def Right():
	"""Moves the cursor one character to the right.
	It will go to the next line if it is at the end of the line..."""
	_editor.Right()

def LineStart(pos=None):
	"""returns the beginning of line where pos is."""
	if pos is None:
		pos=GetSelectionStart()
	return _editor.LineStart(pos)
 
def LineEnd(pos=None):
	"""returns the end of line where pos is"""
	if pos is None:
		pos=GetSelectionEnd()
	return _editor.LineEnd(pos)
def LookAt(pos):
	"""returns the character at pos"""
	return _editor.LookAt(pos)

def MaxPos():
	"""returns the end of test"""
	return _editor.MaxPos()
 
def NextLineStart():
	"""returns a string"""
	return _editor.NextLineStart()

def PosToRowCol(pos):
	"""returns a touple (row,col)"""
	return _editor.PosToRowCol(pos)
def RowColToPos(*args):
	"""returns the pos"""
	return _editor.RowColToPos(args)

def SetSelection(*args):
	"""Sets the selection to (x,y) or x,y"""
	return _editor.SetSelection(args)

def Search(string,startpos,casesensitive=0,backward=0):
	return _editor.Search(string,startpos,casesensitive,backward)
#
# Undo
#
def Undo():
	_editor.Undo()

#
# Redo
#
def Redo():
	_editor.Redo()
#
# Beep
#
def Bell():
	"""Beep!"""
	_editor.Bell()
def SetStyle(s,e,st):
	_editor.SetStyle(s,e,st)
 
######################################################################

def GetSelectionStart():
	"""returns the start of the current selection"""
	return _editor.GetSelection()[0]

# returns the start of the current selection
def GetSelectionEnd():
	return _editor.GetSelection()[1]
#
# @interactive@
#
def FindWordStart(startpos=None):
	if startpos is None:
		startpos=GetSelectionStart()
	(s,e)= _editor.Search('\(^\|[^A-Za-z0-9_]\)[A-Za-z0-9_]', startpos-2,1,1)
	return (s+e)/2

def FindWordEnd(startpos=None):
	if startpos is None:
		startpos=GetSelectionEnd()
	(s,e)=_editor.Search('[A-Za-z0-9_]\([^A-Za-z0-9_]\|$\)', startpos)
	return (s+e)/2

def GotoWordStart(startpos=None):
	Goto(FindWordStart(startpos))
def GotoWordEnd(startpos=None):
	Goto(FindWordEnd(startpos))
def SelectWord():
	SetSelection(FindWordStart(),FindWordEnd())

def KillWord():
	pos=GetSelectionEnd()
	SetSelection(pos,FindWordEnd(pos))
	Cut()

def BackwardKillWord():
	pos=GetSelectionStart()
	SetSelection(FindWordStart(pos),pos)
	Cut()

_specials=['[',']','^','-']
def Zap(char=')'):
	startpos=GetSelectionEnd()
	if char in _specials:
		char='\\%s' % char
	endpos=_editor.Search('[%s]'%char,startpos)[1]
	if endpos >=0:
		SetSelection(startpos,endpos)
		Cut()
	
def Delete():
	DoKey(Token.KeyName2CodeFlags('C-d'))

def Backspace():
	DoKey(Token.KeyName2CodeFlags('Backspace'))

def FilterSelectionOrWord(filter):
	(start,end)=GetSelection()
	if start == end:
		#select the next word
		start=GetSelectionEnd()
		end=FindWordEnd(start)
		#start=FindWordStart(end)
	if(start!=end):
		SetSelection(start,end)
		text=GetSelectionText()
		filtered=filter(text)
		if filtered==text:
			SetSelection(end,end)
		else:
			InsertText(filtered)

def Upcase():
	FilterSelectionOrWord(string.upper)
def Downcase():
	FilterSelectionOrWord(string.lower)
def Swapcase():
	FilterSelectionOrWord(string.swapcase)

def Capitalize():
	FilterSelectionOrWord(lambda str:string.upper(str[:1])+str[1:])
 

def KillLine():
	start=GetSelectionStart()
	end=LineEnd()
	if start==end:
		# kill the newline
		end=end+1
	SetSelection(start,end)
	Cut()

def StartSelect():
	sel_start=GetSelectionStart()

def GetTabWidth():
	return _editor.GetTabWidth() or 4

def SetTabWidth(width):
	return _editor.SetTabWidth(width)

def GetIndentWidth():
	return _editor.GetIndentWidth() or 4

#
# Indent by the IndentWidth if the the beginning of a line..
#
def DoSmartIndent(indent,ch):
	(start,end)=GetSelection()
	repl=ch
	linestart=LineStart(start)
	line=GetText(linestart,start)
	# is there only whitespace up to here?
	if regex.match('^[\t ]*$',line)>=0:
		str=string.expandtabs(line,GetTabWidth())
		str=str + indent * ' '
		repl=Tabify(str,GetTabWidth())
		if repl==line+ch:
			repl=ch
		else:
			SetSelection(linestart,end)
	if repl==ch or repl==line+ch:
		for c in ch:
			DoKeyCode(ord(c),0)
	else:
		InsertText(repl)

def Tabify(s,tabsize):
	if len(s)==0:
		return s
	res = tab = ''
	tabstr=GetTabString()
	for i in range(len(s)):
		c=s[i]
		if c == ' ':
			tab=tab+' '
			if len(tab)==tabsize:
				res=res + tabstr
				tab=''
		else:
			res=res+tab+c
			tab=''
			break
	return res + tab + s[i+1:]

def GetTabString():
	if GetPreference("Sniff.FillWithTabs",1):
		return '\t'
	else:
		return ' ' * GetTabWidth()

def SmartTab():
	DoSmartIndent(GetIndentWidth(),GetTabString())

def SmartSpace():
	DoSmartIndent(1,' ')

def SmartBackspace():
	"""Deleles one character backwards but treats blanks the same way as tabs..."""
	(start,end)=GetSelection()
	repl=''
	linestart=LineStart(start)
	line=GetText(linestart,start)
	# is there only whitespace up to here?
	if regex.match('^[\t ]+$',line)>=0:
		line=string.expandtabs(line,GetTabWidth())
		if (len(line) % GetIndentWidth())==0:
			bs=GetIndentWidth()
		else:
			bs=1
		line=line[:-bs]
		repl=Tabify(line,GetTabWidth())
		SetSelection(linestart,end)
		InsertText(repl)
	else:
		Backspace()

def SmartDelete():
	Delete()

def SmartLeft():
	(start,end)=GetSelection()
	linestart=LineStart(start)
	line=GetText(linestart,start)
	# is there only whitespace up to here?
	if regex.match('^[\t ]+$',line)>=0:
		line=string.expandtabs(line,GetTabWidth())
		if (len(line) % GetIndentWidth())==0:
			SetSelection(linestart,linestart)
			return
	Left()

def SmartRight():
	(start,end)=GetSelection()
	lineEnd=LineEnd(end)
	lineStart=LineStart(end)
	posFromLineEnd=lineEnd-end
	posFromLineStart=end-lineStart
	line=GetText(lineStart,lineEnd)
	# is there only whitespace up to here?
	whiteEnd=regex.match('^[\t ]+',line)
	if whiteEnd>=posFromLineStart:
		expandedLine=string.expandtabs(line[:whiteEnd],GetTabWidth())
		# now find the goal position:
		whiteEndFromRight=len(line)-whiteEnd
		offset=len(expandedLine)%GetIndentWidth()
		newpos=lineStart+whiteEnd-offset
		if end < newpos-1:
			SetSelection(newpos,newpos)
			return
	Right()

# Cursor movements

def GotoNext():
	DoNamedKey('Right')
def GotoPrev():
	DoNamedKey('Left')

def SelectNext():
	DoNamedKey('S-Right')
def SelectPrev():
	DoNamedKey('S-Left')

def GotoNextLine():
	DoNamedKey('Down')
def GotoPrevLine():
	DoNamedKey('Up')

def SelectNextLine():
	DoNamedKey('S-Down')
def SelectPrevLine():
	DoNamedKey('S-Up')


def GotoNextWord():
	DoNamedKey('C-Right')

def GotoPrevWord():
	DoNamedKey('C-Left')

def SelectNextWord():
	DoNamedKey('S-C-Right')

def SelectPrevWord():
	DoNamedKey('S-C-Left')


def GotoPageUp():
	DoNamedKey('C-Up')
def GotoPageDown():
	DoNamedKey('C-Down')
# backward compatible
PageUp=GotoPageUp
PageDown=GotoPageDown

def SelectPageUp():
	DoNamedKey('PageUp')

def SelectPageDown():
	DoNamedKey('PageDown')


def GotoLineStart():
	DoNamedKey('Home')

def GotoLineEnd():
	DoNamedKey('End')
 
def SelectLineStart():
	DoNamedKey('S-Home')
 
def SelectLineEnd():
	DoNamedKey('S-End')


def GotoBeginningOfFile():
	DoNamedKey('C-Home')

def GotoEndOfFile():
	DoNamedKey('C-End')

def SelectBeginningOfFile():
	DoNamedKey('S-C-Home')

def SelectEndOfFile():
	DoNamedKey('S-C-End')
